/*************************************************************
 * @Author: dENGcj                                           *
 * @Version: 0.1.b20210102                                   *
 * @Date: 2020-12-31 23:11                                   *
 * @LastEditTime: 2021-01-02 23:02                           *
 * @Descripttion: Implementation of AD9833 Driver.           *
 *************************************************************/

/*************************************************************
 *         Warning: Read AD9833 Datasheet First.             *
 *************************************************************/

/* Includes------------------------------------------------- */
#include "chilis9833.h"

/* Private Includes----------------------------------------- */

/* Extern Variables----------------------------------------- */

/*************************************************************
 * FSYNC_HIGH and FSYNC_LOW are used as CS signal to AD9833. *
 * A GPIO pin with level control can be used here.           *
 * This two macro must be implemented.                       *
 *************************************************************/
#define FSYNC_HIGH /* Add Code Here */
#define FSYNC_LOW  /* Add Code Here */

/*************************************************************
 * @brief: The initialization of Hardware SPI,which is       *
 *          specified by the MCU used.If software SPI        *
 *          is used,ignore this function.                    *
 * @param: None                                              *
 * @retval: None                                             *
 *************************************************************/
static void chilis9833_SPI_Init(void)
{
    /* Add Code Here */
}

/*************************************************************
 * @brief: Transmit two bytes consecutively to AD9833.       *
 * @param: regBytes- Bitwise OR of two uint8_t bytes.        *
 * @retval: None                                             *
 *************************************************************/
static void chilis9833_SPI_Transmit_2Bytes(uint16_t regBytes)
{
    uint8_t regBytesH = 0;
    uint8_t regBytesL = 0;
    regBytesH = (regBytes & 0xFF00) >> 8;
    regBytesL = regBytes & 0x00FF;
    /* Add Code Here */
}

/*************************************************************
 * @brief: Init AD9833.Init SPI first,and then reset AD9833. *
 *          If AD9833 is reset properly,an analog signal of  *
 *          midscale should output on pin Vout,which is about*
 *          0.3V.                                            *
 * @param: None                                              *
 * @retval: None                                             *
 *************************************************************/
void chilis9833_Init(void)
{
    chilis9833_SPI_Init();
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(CMD_RESET);
    FSYNC_HIGH;
}

/*************************************************************
 * @brief: Reset AD9833.                                     *
 *          If AD9833 is reset properly,an analog signal of  *
 *          midscale should output on pin Vout,which is about*
 *          0.3V.                                            *
 * @param: None                                              *
 * @retval: None                                             *
 *************************************************************/
void chilis9833_Reset(void)
{
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(CMD_RESET);
    FSYNC_HIGH;
}

/*************************************************************
 * @brief: Disable reset.                                    *
 * @param: None                                              *
 * @retval: None                                             *
 *************************************************************/
void chilis9833_Clear_Reset(void)
{
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(CMD_CLEAR_RESET);
    FSYNC_HIGH;
}

/*************************************************************
 * @brief: Set Frequency of porper Freq Register(28bit).Both *
 *          MSB(14bit) and LSB(14bit).                       *
 * @param: freqX- The frequency register which can be        *
 *          specified as Freq0 or Freq1.                     *
 *          If Freq0,use macro REG_WRITE_FREQ0               *
 *          If Freq1,use macro REG_WRITE_FREQ1               *
 *         freqValue- The value of frequency in Hz.          *
 * @retval: None                                             *
 *************************************************************/
void chilis9833_Write_Freq_2Bytes(uint16_t freqX, uint32_t freqValue)
{
    uint32_t regFreq = 0;
    uint16_t regFreqMSB = 0;
    uint16_t regFreqLSB = 0;
    regFreq = freqValue * 256 / MCLK;
    regFreqMSB = (regFreq & 0x0FFFC000) >> 14;
    regFreqLSB = regFreq & 0x00003FFF;
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(CMD_WRITE_LSB_MSB | CMD_RESET);
    FSYNC_HIGH;
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(regFreqLSB | freqX);
    FSYNC_HIGH;
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(regFreqMSB | freqX);
    FSYNC_HIGH;
}

/*************************************************************
 * @brief: Set MSB(14bit) of porper Freq Register(28bit).    *
 * @param: freqX- The frequency register which can be        *
 *          specified as Freq0 or Freq1.                     *
 *          If Freq0,use macro REG_WRITE_FREQ0               *
 *          If Freq1,use macro REG_WRITE_FREQ1               *
 *         freqValue- The value of frequency in Hz.          *
 * @retval: None                                             *
 *************************************************************/
void chilis9833_Write_Freq_MSB(uint16_t freqX, uint32_t freqValue)
{
    uint32_t regFreq = 0;
    uint16_t regFreqMSB = 0;
    regFreq = freqValue * 256 / MCLK;
    regFreqMSB = (regFreq & 0x3FFF0000) >> 16;
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(CMD_WRITE_MSB);
    FSYNC_HIGH;
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(regFreqMSB | freqX);
    FSYNC_HIGH;
}

/*************************************************************
 * @brief: Set LSB(14bit) of porper Freq Register(28bit).    *
 * @param: freqX- The frequency register which can be        *
 *          specified as Freq0 or Freq1.                     *
 *          If Freq0,use macro REG_WRITE_FREQ0               *
 *          If Freq1,use macro REG_WRITE_FREQ1               *
 *         freqValue- The value of frequency in Hz.          *
 * @retval: None                                             *
 *************************************************************/
void chilis9833_Write_Freq_LSB(uint16_t freqX, uint32_t freqValue)
{
    uint32_t regFreq = 0;
    uint16_t regFreqLSB = 0;
    regFreq = freqValue * 256 / MCLK;
    regFreqLSB = regFreq & 0x0000FFFF;
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(CMD_WRITE_MSB);
    FSYNC_HIGH;
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(regFreqLSB | freqX);
    FSYNC_HIGH;
}

/*************************************************************
 * @brief: Set Phase of porper Phase Register(12bit).        *
 * @param: phaseX- The Phase register which can be specified *
 *          as Phase0 or Phase1.                             *
 *          If Phase0,use macro REG_WRITE_PHASE0             *
 *          If Phase1,use macro REG_WRITE_PHASE1             *
 *         phaseValue- The value of Phase in radian.         *
 * @retval: None                                             *
 *************************************************************/
void chilis9833_Write_Phase(uint16_t phaseX, uint16_t phaseValue)
{
    uint16_t regPhase = 0;
    regPhase = (uint16_t)(phaseValue * 4096 / 2 / 3.14159);
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(regPhase | phaseX);
    FSYNC_HIGH;
}

/*************************************************************
 * @brief: Set the output of AD9833.                         *
 * @param: freqX- The frequency register which can be        *
 *          specified as Freq0 or Freq1.                     *
 *          If Freq0,use macro REG_WRITE_FREQ0               *
 *          If Freq1,use macro REG_WRITE_FREQ1               *
 *         phaseX- The Phase register which can be           *
 *          specified as Phase0 or Phase1.                   *
 *          If Phase0,use macro REG_WRITE_PHASE0             *
 *          If Phase1,use macro REG_WRITE_PHASE1             *
 *         outMode- Output Mode of AD9833,which can be       *
 *          triangle\sinusoidal\square with following        *
 *          macro used:                                      *
 *          CMD_OUTPUT_TRIANGLE                              *
 *          CMD_OUTPUT_SINUSOIDAL                            *
 *          CMD_OUTPUT_MSB\CMD_OUTPUT_MSB_DIV2               *
 * @retval: None                                             *
 *************************************************************/
void chilis9833_Output_Mode(uint16_t freqX, uint16_t phaseX, uint16_t outMode)
{
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(freqX | phaseX | outMode);
    FSYNC_HIGH;
}

/*************************************************************
 * @brief: Set control bits of AD9833.                       *
 * @param: ctrlBit- Control bits in Control register,        *  
 *          Bitwise OR of different Bits.                    *
 * @retval: None                                             *
 *************************************************************/
void chilis9833_Set_Control_Bits(uint16_t ctrlBit)
{
    FSYNC_HIGH;
    FSYNC_LOW;
    chilis9833_SPI_Transmit_2Bytes(ctrlBit);
    FSYNC_HIGH;
}
